import java.io.IOException;
import java.lang.System;
import java.util.logging.*;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicLong;


/*
 * 事务统计
 *    Reset():         重置统计状态
 *    Start():         事务启动，获取时间戳
 *    End(startTime):  事务结束，进行统计
 *    Calculate():     计算统计结果:  Map<String, Long> 
 *                        "count":   事务运行总次数
 *                        "time":    事务运行总时间
 *                        "maxTime": 最长事务运行时间
 *                        "minTime": 最短事务运行时间
 *                        "avgTime": 平均事务运行时间
 *
 *    父线程实例化一个，调用Reset()重置与Calculate()获取结果。 
 *    众多子线程使用父线程实例化的对象，并发调用Start、End进行计数。
 */
class XactStatistic {
    private long totalCount;
    private long totalRunTime;
    private long maxRunTime;
    private long minRunTime;
    private long startTime;
    
    public XactStatistic() {
        reset();
    }
    
    public void reset() {
        totalCount = 0;
        totalRunTime = 0;
        maxRunTime = 0;
        minRunTime = 0;
        startTime = System.currentTimeMillis();
    }
    
    public long start() {
        return System.currentTimeMillis();
    }
    
    public void end(long startTime) {
        long runTime = System.currentTimeMillis() - startTime;
        synchronized(this) {
            totalCount++;
            totalRunTime += runTime;
            maxRunTime = Math.max(maxRunTime, runTime);
            if (minRunTime == 0) {
                minRunTime = runTime;
            } else {
                minRunTime = Math.min(minRunTime, runTime);
            }
        }
    }
    
    public Map<String, Long> calculate() {
        Map<String, Long> map = new HashMap<String, Long>();
        
	long runTime = (System.currentTimeMillis() - startTime) / 1000;
        long totalCount   = this.totalCount;
        long totalRunTime = this.totalRunTime;
        long maxRunTime   = this.maxRunTime;
        long minRunTime   = this.minRunTime;
        
        if (totalCount == 0) {
            map.put("count", (long)0);
            map.put("time", (long)0);
            map.put("runTime", (long)0);
            map.put("maxTime", (long)0);
            map.put("minTime", (long)0);
            map.put("avgTime", (long)0);
        } else {
            map.put("count", totalCount);
            map.put("time", totalRunTime);
            map.put("runTime", runTime);
            map.put("maxTime", maxRunTime);
            map.put("minTime", minRunTime);
            map.put("avgTime", totalRunTime/totalCount);
        }
        return map;
    }
};


/*
 * TPS统计
 *
 *    CountOne():  对计数进行 +1。 
 *                 接口并发安全。
 *    Calculate(): 计算tps。此接口不要并发调用，但可以与CountOne()并发
 *                 计算结果： Map<String, Long> 
 *                   "time":      总体运行时间
 *                   "count":     总计数次数
 *                   "avg":       总平均速度
 *                   "count300s": 最近300秒统的计数次数
 *                   "avg300s":   最近300秒统的平均速度
 *                   "count60s":  最近60秒的计数次数
 *                   "avg60s":    最近60秒的平均速度
 *                   "speed":     最近1秒内的计数次数
 *    Reset():     重置。
 *
 *    父线程实例化一个，调用Reset()重置与Calculate()获取结果。 
 *    众多子线程使用父线程实例化的对象，并发调用CountOne进行计数。
 */
class TpsStatistic {
    private long startTime;
    private AtomicLong counter;
    private int countHistSize;
    private int countHistIdx;
    private long countHistory[];
    
    public TpsStatistic() {
        reset();
    }
    
    public void reset() {
        startTime = System.currentTimeMillis();
        counter = new AtomicLong(0);
        
        countHistSize = 300;
        countHistory = new long[countHistSize];
        countHistIdx = 0;
    }
    
    public long countOne() {
        return counter.getAndIncrement();
    }
    
    public Map<String, Long> calculate() {
        Map<String, Long> map = new HashMap<String, Long>();
        
        long resCount = counter.get();
        long resRunTime = Math.max(((System.currentTimeMillis() - startTime) / 1000), 1);
        
        long resCount001c = resCount - countHistory[(countHistIdx - 1   + countHistSize) % countHistSize];
        long resCount060c = resCount - countHistory[(countHistIdx - 60  + countHistSize) % countHistSize];
        long resCount300c = resCount - countHistory[(countHistIdx - 300 + countHistSize) % countHistSize];
        countHistory[countHistIdx] = resCount;
        countHistIdx = (countHistIdx + 1) % countHistSize;
        
        long resAvg001c = resCount001c;
        long resAvg060c = resCount060c / (resRunTime < 60 ? resRunTime : 60);
        long resAvg300c = resCount300c / (resRunTime < 300 ? resRunTime : 300);
        long resAvg = resCount / resRunTime;
        
        map.put("time", resRunTime);
        map.put("count", resCount);
        map.put("avg", resAvg);
        map.put("count300s", resCount300c);
        map.put("avg300s", resAvg300c);
        map.put("count60s", resCount060c);
        map.put("avg60s", resAvg060c);
        map.put("speed", resAvg001c);
        
        return map;
    }
};


/*
 * 事务统计（单线程）
 *    totalCount：执行次数
 *    totalTime： 累计执行时间
 *    avgRunTime：平均执行时间
 *    maxRunTime：最长执行时间
 *    minRunTime：最短执行时间
 *
 * 单线程使用，不加锁。
 */
class XactStatisticSimple {
    private long totalCount;
    private long totalTime;
    private long avgRunTime;
    private long maxRunTime;
    private long minRunTime;
    
    private long startTime;

    public XactStatisticSimple() {
        totalCount = 0;
        totalTime = 0;
        maxRunTime = 0;
        minRunTime = 0;
    }

    public void start() {
        startTime = System.currentTimeMillis();
    }

    public void end() {
        long runTime = System.currentTimeMillis() - startTime;

        totalCount++;
        totalTime += runTime;
        maxRunTime = Math.max(maxRunTime, runTime);
        if (minRunTime == 0) {
                minRunTime = runTime;
        } else {
            minRunTime = Math.min(minRunTime, runTime);
        }
    }
    
    public Map<String, Long> calculate() {
        Map<String, Long> map = new HashMap<String, Long>();
        
        long totalCount   = this.totalCount;
        long totalTime = this.totalTime;
        long maxRunTime   = this.maxRunTime;
        long minRunTime   = this.minRunTime;
        
        if (totalCount == 0) {
            map.put("count", (long)0);
            map.put("totalTime", (long)0);
            map.put("maxTime", (long)0);
            map.put("minTime", (long)0);
            map.put("avgTime", (long)0);
        } else {
            map.put("count", totalCount);
            map.put("totalTime", totalTime);
            map.put("maxTime", maxRunTime);
            map.put("minTime", minRunTime);
            map.put("avgTime", totalTime/totalCount);
        }
        return map;
    }
};

